package com.yellowpage.white.dao;

import java.io.Serializable;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.sql.Connection;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.hibernate.FlushMode;
import org.hibernate.HibernateException;
import org.hibernate.SQLQuery;
import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.springframework.orm.ObjectRetrievalFailureException;
import org.springframework.orm.hibernate4.HibernateCallback;
import org.springframework.orm.hibernate4.SessionFactoryUtils;
import org.springframework.orm.hibernate4.support.HibernateDaoSupport;

public class BaseDaoHibernateImpl<E, PK extends Serializable> extends
		HibernateDaoSupport implements BaseDao<E, PK> {
	protected final Log log = LogFactory.getLog(getClass());
	private Class<E> persistentClass;

	 private SessionFactory sessionFactory; 

	public BaseDaoHibernateImpl() {
	}

	public BaseDaoHibernateImpl(Class<E> persistentClass) {
		this.persistentClass = persistentClass;

		/** Hibernate4取得SessionFactory的方法 */
		// Configuration cfg = new Configuration().configure();
		// ServiceRegistry serviceRegistry = new
		// ServiceRegistryBuilder().applySettings(cfg.getProperties()).buildServiceRegistry();
		// sessionFactory = cfg.buildSessionFactory(serviceRegistry);
	}

	@SuppressWarnings("unchecked")
	public List<E> getAll() {
		return super.getHibernateTemplate().loadAll(this.persistentClass);
	}

	@SuppressWarnings("unchecked")
	public List getObjectListByConditions(String sql,
			Object[] conditionValueList) {
		return super.getHibernateTemplate().find(sql, conditionValueList);
	}

	@SuppressWarnings("unchecked")
	public E get(PK id) {
		try {
			E entity = (E) super.getHibernateTemplate().get(
					this.persistentClass, id);

			if (entity == null) {
				throw new ObjectRetrievalFailureException(this.persistentClass,
						id);
			}
			return entity;
		} catch (Exception e) {
			e.printStackTrace();
		}
		return null;

	}

	@SuppressWarnings("unchecked")
	public boolean exists(PK id) {
		E entity = (E) super.getHibernateTemplate().get(this.persistentClass,
				id);
		if (entity == null) {
			return false;
		} else {
			return true;
		}
	}

	private String getMethodName(String fieldName, String methodBegin) {

		if (fieldName != null)
			return methodBegin + fieldName.substring(0, 1).toUpperCase()
					+ fieldName.substring(1);

		return "";
	}

	private E trimObjectFieldValues(E object) {

		try {
			Field[] fields = object.getClass().getDeclaredFields();
			if (fields != null) {
				for (int i = 0; i < fields.length; i++) {

					String type = fields[i]
							.getType()
							.toString()
							.substring(
									fields[i].getType().toString()
											.lastIndexOf('.') + 1);
					if (type.equals("String")) {
						String getmethod = getMethodName(fields[i].getName(),
								"get");
						String setmethod = getMethodName(fields[i].getName(),
								"set");
						// System.out.println(getmethod+"||"+setmethod);
						Method rgetmethod = object.getClass().getMethod(
								getmethod);
						Method rsetmethod = object.getClass().getMethod(
								setmethod, new Class[] { String.class });
						if (rgetmethod != null && rsetmethod != null) {
							String getvalue = (String) rgetmethod
									.invoke(object);
							System.out.println(fields[i].getName() + ":" + "|"
									+ getvalue + "|");
							if (getvalue != null)
								rsetmethod.invoke(object,
										new Object[] { getvalue.trim() });
						}
						// String getvalue1 = (String)rgetmethod.invoke(object);
						// System.out.println("after value : " +
						// "|"+getvalue1+"|");
					}

				}
			}
		} catch (Exception e) {
			e.printStackTrace();
		}

		return object;
	}

	public boolean save(E object) {
		
		//return this.getCurrentSession().save(o);  
		
		object = trimObjectFieldValues(object);
		
		Session session = super.getHibernateTemplate().getSessionFactory().openSession();
		session.setFlushMode(FlushMode.AUTO);
		
		Serializable id =  session.save(object);
		
		session.flush();
		if (id != null) {
			return true;
		} else {
			return false;
		}
	}

	public void save(List<E> objects) {
		Session session = super.getHibernateTemplate().getSessionFactory().openSession();
		session.setFlushMode(FlushMode.AUTO);
		
		for (E object : objects) {
			object = trimObjectFieldValues(object);
			session.save(object);
		}
		
		session.flush();
	}

	public void update(E object) {
		object = trimObjectFieldValues(object);
		
		Session session = super.getHibernateTemplate().getSessionFactory().openSession();
		session.setFlushMode(FlushMode.AUTO);
		
		session.update(object);
		
		session.flush();
		//super.getHibernateTemplate().update(object);
	}

	public void update(List<E> objects) {       
		
		Session session = super.getHibernateTemplate().getSessionFactory().openSession();
		session.setFlushMode(FlushMode.AUTO);
		
		for (E object : objects) {
			object = trimObjectFieldValues(object);
			session.update(object);
		}
		
		session.flush();

	}

	public void remove(PK id) {
		
		Session session = super.getHibernateTemplate().getSessionFactory().openSession();
		session.setFlushMode(FlushMode.AUTO);
		
		session.delete(this.get(id));
		
		session.flush();
	}

	public void remove(List<PK> ids) {
		Session session = super.getHibernateTemplate().getSessionFactory().openSession();
		session.setFlushMode(FlushMode.AUTO);
		
		for (PK id : ids) {	
			session.delete(this.get(id));
		}
		session.flush();
	}

	public QueryAssistantSQL newQueryAssistantSQL(String sql) {
		return new QueryAssistantSQL(sql);
	}

	public Connection getConnection() {
		Connection conn = null;
		try {
			conn = SessionFactoryUtils.getDataSource(getSessionFactory())
					.getConnection();
		} catch (Exception e) {
			e.printStackTrace();
		}

		return conn;
	}

	public static void main(String[] args) {
		BaseDaoHibernateImpl impl = new BaseDaoHibernateImpl();

	}

	@Override
	public void remove(String sql, Object[] params) {
		final String delSql = sql;
		final Object[] fParams = params;
		this.getHibernateTemplate().execute(new HibernateCallback() {
			public Object doInHibernate(Session session)
					throws HibernateException {

				SQLQuery query = session.createSQLQuery(delSql);
				for (int i = 0; i <= fParams.length - 1; i++) {
					query.setParameter(i, fParams[i]);
				}
				int count = query.executeUpdate();

				log.info("count==" + count);

				return true;
			}
		});

	}

	public List<Map> query(final QueryAssistantSQL sqlAssistant, Map queryMap) {

		if (queryMap == null)
			queryMap = new HashMap();
		final Map tempMap = queryMap;

		Connection conn = null;
		try {
			// conn = session.connection();
			conn = SessionFactoryUtils.getDataSource(getSessionFactory())
					.getConnection();
			List<Map> resultList = sqlAssistant.query(conn, tempMap);

			return resultList;
		} catch (Exception e) {
			e.printStackTrace();
		} finally {
			if (conn != null) {
				try {
					conn.close();
				} catch (Exception e) {
					e.printStackTrace();
				}
			}
		}

		return null;

	}

	public List<Map> query(final String finalSql, Map queryMap) {

		if (queryMap == null)
			queryMap = new HashMap();
		final Map tempMap = queryMap;

		Connection conn = null;
		try {
			conn = SessionFactoryUtils.getDataSource(getSessionFactory())
					.getConnection();
			QueryAssistantSQL sqlAssistant = newQueryAssistantSQL(finalSql);
			List<Map> resultList = sqlAssistant.query(conn, tempMap);

			return resultList;
		} catch (Exception e) {
			e.printStackTrace();
		} finally {
			if (conn != null) {
				try {
					conn.close();
				} catch (Exception e) {
					e.printStackTrace();
				}
			}
		}

		return null;

	}

}
